﻿using System;
using System.Collections.Generic;
using System.Xml;


/*  TODO:
 *      constructor for species!
 */


namespace ClassLibrary
{
    /* Class for describing species
     * which has sexual reproduction 
    */
    public class Species
    {
        public int id { set; get; }
        public string name { set; get; }
        public string path { set; get; }


        public ChromosomeTable sp_chromosome_table;
        public GeneTable sp_gene_table;
        public ChromosomeGeneLink sp_chomosome_gene_link;
        public PhenotypeTable sp_phenotype_table;
        public GenomePhenotypeLink sp_genome_phenotype_link;
        public NaturalSelectionTable sp_natural_selection_table;
        public CrossingoverLink sp_crossingover_link;
        

        public Dictionary<string, NaturalSelectionLink> sp_natural_selection_links = new Dictionary<string, NaturalSelectionLink>();
        public Dictionary<string, ReproductionLink> sp_reproduction_links = new Dictionary<string, ReproductionLink>();

        // flag that indicates if species is described complerly
        public bool bound { set; get; }


        // populations
        public int amount_populations { set; get; }
        public Dictionary<string, Population> massive_populations = new Dictionary<string, Population>();


        /* Constructor */
        public Species(string path_to_species)
        {
            bound = false;
            path = path_to_species;

            // open XML file
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(System.IO.File.ReadAllText(path_to_species));

            // reading attributes of the first node
            name = doc.DocumentElement.GetAttribute("Name");
            amount_populations = Convert.ToInt32(doc.DocumentElement.GetAttribute("AmountPopulations"));


            // reading all data about populations
            if (amount_populations != 0)
            {
                // reading "populations" node                
                foreach (XmlNode x in doc.GetElementsByTagName("population"))
                {
                    massive_populations.Add(x.Attributes[0].Value, new Population(x.Attributes[0].Value, this));
                }
            }
        }


        /*
         * Method 
         * Args : two tables and one link
         * Does: bind species to tables
        */
        public void bindSpecies(ChromosomeTable ch_table, GeneTable ge_table,
                                ChromosomeGeneLink ch_ge_link, PhenotypeTable ph_table,
                                GenomePhenotypeLink ge_ph_link, NaturalSelectionTable na_se_table,
                                CrossingoverLink cr_link, Dictionary<string, NaturalSelectionLink> na_se_links,
                                Dictionary<string, ReproductionLink> re_links)
        {
            sp_chromosome_table = ch_table;
            sp_gene_table = ge_table;
            sp_chomosome_gene_link = ch_ge_link;
            sp_phenotype_table = ph_table;
            sp_genome_phenotype_link = ge_ph_link;
            sp_natural_selection_table = na_se_table;
            sp_crossingover_link = cr_link;
            sp_natural_selection_links = na_se_links;
            sp_reproduction_links = re_links;

            bound = true;
        }

        /* 
         * Method 
         * Does: initialization
        */
        public void initSpecies()
        {
            foreach (string key in massive_populations.Keys)
            {
                massive_populations[key].initPopulation();
            }
        }


        /* 
         * Method 
         * Args: no
         * Does: countins phenotype characteristics
        */
        public void spCountPhenotypeCharacteristics()
        {
            foreach(string key in massive_populations.Keys)
            {
                massive_populations[key].popCountPhenotypeCharacteristics();
            }
        }


        /* 
         * Method
         * Args: no
         * Does: counts event vectors
        */
        public void spGetEvents()
        {
            foreach (string key in massive_populations.Keys)
            {
                massive_populations[key].popGetEvents();
            }
        }


        /* 
         * Method
         * Args: no
         * Does: makes calculations for next step of modelling
        */
        public void spDoNextModellingStep()
        {
            foreach (string key in massive_populations.Keys)
            {
                massive_populations[key].popDoNextModellingStep();
            }
        }


        /* 
         * Method
         * Args: no
         * Does: makes all populations gather statistics
        */
        public void spGatherOneStepStatistics()
        {
            foreach (string key in massive_populations.Keys)
            {
                massive_populations[key].popGatherOneStepStatistics();
            }
        }


        /* 
         * Method
         * Args: no
         * Does: makes all populations to take natural selection links
        */
        public void spTakeNaturalSelectionLinks()
        {
            foreach (Population population in massive_populations.Values)
            {
                string path_to_population_natural_selection_link = population.getPathToNaturalSelectionLink();
                NaturalSelectionLink population_natural_selection_link = sp_natural_selection_links[path_to_population_natural_selection_link];

                population.setNaturalSelectionLink(population_natural_selection_link);
            }
        }


        /* 
         * Method
         * Args: no
         * Does: makes all populations to take reproduction links
        */
        public void spTakeReproductionLinks()
        {
            foreach (Population population in massive_populations.Values)
            {
                string path_to_population_reproduction_link = population.getPathToReproductionLink();
                ReproductionLink population_reproduction_link = sp_reproduction_links[path_to_population_reproduction_link];

                population.setReproductionLink(population_reproduction_link);
            }
        }
    }
}